import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;

public class SwingCalcUI extends UI implements ActionListener, FocusListener  {

	//************  Constructor and start method required by MVC ***************************/

	private CalcInterface myCalc;

	public SwingCalcUI(Model m) {

		myCalc = (CalcInterface)m;

	}

	public void start() {
		composeUI();
		refreshFromModel();
	}

	//*************   This is UI composition only **********************/

	private JTextField xField;
	private JTextField yField;
	private JTextField zField;
	private JButton clearButton;

	private void composeUI() {
        //Create and set up the window.
        JFrame viewFrame = new JFrame("See a calc!");
        viewFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        viewFrame.setSize(new Dimension(120, 40));
        JPanel viewPanel = new JPanel(new FlowLayout());

        //Create widgets.
        xField = new JTextField(10);
        yField = new JTextField(10);
        zField = new JTextField(10);
        clearButton = new JButton("Clear");

        //Add the widgets to the panel
        viewPanel.add(xField);
        viewPanel.add(new JLabel("/", SwingConstants.CENTER));
        viewPanel.add(yField);
        viewPanel.add(new JLabel("=", SwingConstants.CENTER));
        viewPanel.add(zField);
        viewPanel.add(clearButton);

       //Add the panel to the window.
        viewFrame.getContentPane().add(viewPanel, BorderLayout.CENTER);
        JFrame.setDefaultLookAndFeelDecorated(true);

		//Display the window.
        viewFrame.pack();
        viewFrame.setVisible(true);

        // Let my actionPerformed method handle events from these fields
        xField.addActionListener(this);
        yField.addActionListener(this);
        zField.addActionListener(this);
        clearButton.addActionListener(this);
        xField.addFocusListener(this);
        yField.addFocusListener(this);
        zField.addFocusListener(this);
    }

    public void actionPerformed(ActionEvent event) { myEventHandler(event); }
	public void focusGained(FocusEvent event){}
	public void focusLost(FocusEvent event){ myEventHandler(event); }

	/****************************************************************************/
	/*  This is all about the UI/model interaction -- all interaction mediated */
	/*  by the event handler and the observer/observable update method         */
	/***************************************************************************/

	private void refreshFromModel(boolean x, boolean y, boolean z) {
		if (x) xField.setText(new Double(myCalc.getX()).toString());
		if (y) yField.setText(new Double(myCalc.getY()).toString());
		if (z) zField.setText(new Double(myCalc.getZ()).toString());
	}

	private void refreshToModel(boolean x, boolean y, boolean z) {
		try {
			if (x) myCalc.setX(Double.parseDouble(xField.getText()));
			try {
				if (y) myCalc.setY(Double.parseDouble(yField.getText()));
			} catch (IllegalArgumentException e) {
				JOptionPane.showMessageDialog(null, "Divide by zero not allowed");
				refreshFromModel(false, true, false);
			}
			if (z) myCalc.setZ(Double.parseDouble(zField.getText()));
		} catch (NumberFormatException e) {
			refreshFromModel();
		}
	}

	private void refreshFromModel() {
		refreshFromModel(true, true, true);
	}

	/* Specify what events should cause which Model / GUI transfers */
	private void myEventHandler(AWTEvent event) {
	   if (event.getSource() == xField)      { refreshToModel(true, false, false); }
	   if (event.getSource() == yField)      { refreshToModel(false, true, false); }
	   if (event.getSource() == zField)      { refreshToModel(false, false, true); }
	   if (event.getSource() == clearButton) { myCalc.clear(); }
	}

	public void update(Observable who, Object what) {
		if (what.equals("x")) { refreshFromModel(true, false, false); }
		if (what.equals("y")) { refreshFromModel(false, true, false); }
		if (what.equals("z")) { refreshFromModel(false, false, true); }
	}

}
